<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * CodeIgniter REST Class
 *
 * Mske REST requests to RESTful services with simple syntax.
 *
 * @package        	CodeIgniter
 * @subpackage    	Libraries
 * @category    	Libraries
 * @author        	Philip Sturgeon
 * @created			04/06/2009
 * @license         http://philsturgeon.co.uk/code/dbad-license
 * @link			http://getsparks.org/packages/restclient/show
 */
class REST_Caller {

    protected $_ci;
    protected $supported_formats = array(
        'xml' => 'application/xml',
        'json' => 'application/json',
        'serialize' => 'application/vnd.php.serialized',
        'php' => 'text/plain',
        'csv' => 'text/csv'
    );
    protected $auto_detect_formats = array(
        'application/xml' => 'xml',
        'text/xml' => 'xml',
        'application/json' => 'json',
        'text/json' => 'json',
        'text/csv' => 'csv',
        'application/csv' => 'csv',
        'application/vnd.php.serialized' => 'serialize'
    );
    protected $rest_server = 'http://codeigniter.local/';
    protected $format;
    protected $mime_type = 'text/plain';
    protected $http_auth = 'digest';
    protected $http_user = 'admin';
    protected $http_pass = '123456';
    protected $response_string;

    function __construct($config = array()) {
        $this->_ci = & get_instance();
        // Load the cURL spark which this is dependant on
        $this->_ci->load->library('curl');
        // If a URL was passed to the library
        empty($config) OR $this->initialize($config);
    }

    function __destruct() {
        $this->_ci->curl->set_defaults();
    }

    public function initialize($config) {
        $this->rest_server = @$config['server'];

        if (substr($this->rest_server, -1, 1) != '/') {
            $this->rest_server .= '/';
        }

        isset($config['http_auth']) && $this->http_auth = $config['http_auth'];
        isset($config['http_user']) && $this->http_user = $config['http_user'];
        isset($config['http_pass']) && $this->http_pass = $config['http_pass'];
    }

    /**
     * ham tao chu ky dien tu
     *
     * @param mixed $method
     * @param mixed $url
     * @param mixed $getArgs
     * @param mixed $postArgs
     * @param mixed $private_key
     */
    function makeSignature($method, $url, $getArgs = array(), $postArgs = array(), $private_key_path) {
        $private_key = file_get_contents($private_key_path);
        if ($getArgs) {
            ksort($getArgs);
            $getArgs = urlencode(http_build_query($getArgs));
        }
        if ($postArgs) {
            ksort($postArgs);
            $postArgs = urlencode(http_build_query($postArgs));
        }
        $url = parse_url($url, PHP_URL_PATH);
        $method = strtoupper($method);
        $data = $method . '&' . urlencode($url) . '&' . $getArgs . '&' . $postArgs;
        openssl_sign($data, $signature, $private_key, OPENSSL_ALGO_SHA1);
        return urlencode(base64_encode($signature));
    }

    public function get($uri, $params = array(), $format = NULL) {
        if ($params) {
            $uri .= '?' . (is_array($params) ? http_build_query($params) : $params);
        }
        return $this->_call('get', $uri, NULL, $format);
    }

    public function post($uri, $params = array(), $format = NULL) {
        return $this->_call('post', $uri, $params, $format);
    }

    public function put($uri, $params = array(), $format = NULL) {
        return $this->_call('put', $uri, $params, $format);
    }

    public function delete($uri, $params = array(), $format = NULL) {
        return $this->_call('delete', $uri, $params, $format);
    }

    public function api_key($key, $name = 'X-API-KEY') {
        $this->_ci->curl->http_header($name, $key);
    }

    public function language($lang) {
        if (is_array($lang)) {
            $lang = implode(', ', $lang);
        }
        $this->_ci->curl->http_header('Accept-Language', $lang);
    }

    protected function _call($method, $uri, $params = array(), $format = NULL) {
        
        if ($format !== NULL) {
            $this->format($format);
        }
        $this->_set_headers();
        // Initialize cURL session
        $this->_ci->curl->create($this->rest_server . $uri);
        //var_dump($params);
        //die($this->rest_server .$uri);
        // If authentication is enabled use it
        if ($this->http_auth != '' && $this->http_user != '') {
            $this->_ci->curl->http_login($this->http_user, $this->http_pass, $this->http_auth);
        }
        // We still want the response even if there is an error code over 400
        $this->_ci->curl->option('failonerror', FALSE);
        // Call the correct method with parameters
        $this->_ci->curl->{$method}($params);

        //$this->_ci->load->model('log_rest_caller_m');
//        $log_id=$this->_ci->log_rest_caller_m->insert(array(
//        	'uri'=>$uri
//        	,'method'=>$method
//        	,'params'=>json_encode($params)
//        	,'response'=>null
//        	,'time'=>time()
//        ));
        // Execute and return the response from the REST server
        $response = $this->_ci->curl->execute();
        //var_dump($response);
        //die('dd');
        //$this->_ci->log_rest_caller_m->update($log_id,array(
//        	'response'=>json_encode($response)
//        	,'code'=>$this->info('http_code')
//        ));
        // Format and return
        return $this->_format_response($response);
    }

    // If a type is passed in that is not supported, use it as a mime type
    public function format($format) {
        if (array_key_exists($format, $this->supported_formats)) {
            $this->format = $format;
            $this->mime_type = $this->supported_formats[$format];
        } else {
            $this->mime_type = $format;
        }
        return $this;
    }

    public function debug() {
        $request = $this->_ci->curl->debug_request();
        echo "=============================================<br/>\n";
        echo "<h2>REST Test</h2>\n";
        echo "=============================================<br/>\n";
        echo "<h3>Request</h3>\n";
        echo $request['url'] . "<br/>\n";
        echo "=============================================<br/>\n";
        echo "<h3>Response</h3>\n";
        if ($this->response_string) {
            echo "<code>" . nl2br(htmlentities($this->response_string)) . "</code><br/>\n\n";
        } else {
            echo "No response<br/>\n\n";
        }
        echo "=============================================<br/>\n";
        if ($this->_ci->curl->error_string) {
            echo "<h3>Errors</h3>";
            echo "<strong>Code:</strong> " . $this->_ci->curl->error_code . "<br/>\n";
            echo "<strong>Message:</strong> " . $this->_ci->curl->error_string . "<br/>\n";
            echo "=============================================<br/>\n";
        }
        echo "<h3>Call details</h3>";
        echo "<pre>";
        print_r($this->_ci->curl->info);
        echo "</pre>";
    }

    // Return HTTP status code
    public function status() {
        return $this->info('http_code');
    }

    // Return curl info by specified key, or whole array
    public function info($key = null) {
        return $key === null ? $this->_ci->curl->info : @$this->_ci->curl->info[$key];
    }

    // Set custom options
    public function option($code, $value) {
        $this->_ci->curl->option($code, $value);
    }

    protected function _set_headers() {
        $this->_ci->curl->http_header('Accept: ' . $this->mime_type);
    }

    protected function _format_response($response) {
        $this->response_string = & $response;
        // It is a supported format, so just run its formatting method
        if (array_key_exists($this->format, $this->supported_formats)) {
            return $this->{"_" . $this->format}($response);
        }
        // Find out what format the data was returned in
        $returned_mime = @$this->_ci->curl->info['content_type'];
        // If they sent through more than just mime, stip it off
        if (strpos($returned_mime, ';')) {
            list($returned_mime) = explode(';', $returned_mime);
        }
        $returned_mime = trim($returned_mime);
        if (array_key_exists($returned_mime, $this->auto_detect_formats)) {
            return $this->{'_' . $this->auto_detect_formats[$returned_mime]}($response);
        }
        return $response;
    }

    // Format XML for output
    protected function _xml($string) {
        return $string ? (array) simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA) : array();
    }

    // Format HTML for output
    // This function is DODGY! Not perfect CSV support but works with my REST_Controller
    protected function _csv($string) {
        $data = array();
        // Splits
        $rows = explode("\n", trim($string));
        $headings = explode(',', array_shift($rows));
        foreach ($rows as $row) {
            // The substr removes " from start and end
            $data_fields = explode('","', trim(substr($row, 1, -1)));

            if (count($data_fields) == count($headings)) {
                $data[] = array_combine($headings, $data_fields);
            }
        }
        return $data;
    }

    // Encode as JSON
    protected function _json($string) {
        return json_decode(trim($string));
    }

    // Encode as Serialized array
    protected function _serialize($string) {
        return unserialize(trim($string));
    }

    // Encode raw PHP
    protected function _php($string) {
        $string = trim($string);
        $populated = array();
        eval("\$populated = \"$string\";");
        return $populated;
    }

}

/* End of file REST.php */
/* Location: ./application/libraries/REST.php */